home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / testdisk / src / ntfs_dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-01-09  |  14.6 KB  |  484 lines

  1. /**
  2.  * ntfs_dir.c - Part of the TestDisk project.
  3.  *
  4.  * Copyright (c) 2004 Christophe Grenier
  5.  *
  6.  * Original version comes from the Linux-NTFS project.
  7.  * Copyright (c) 2003 Lode Leroy
  8.  * Copyright (c) 2003 Anton Altaparmakov
  9.  * Copyright (c) 2003 Richard Russon
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program (in the main directory of the Linux-NTFS
  23.  * distribution in the file COPYING); if not, write to the Free Software
  24.  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  25.  */
  26. #ifdef HAVE_NTFSPROGS
  27. #include "config.h"
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <time.h>
  32. #include <string.h>
  33. #include <errno.h>
  34.  
  35. #include "layout.h"
  36. #include "attrib.h"
  37. #define MAX_PATH    1024
  38. #define PATH_SEP      '/'
  39. #define NTFS_DT_DIR               4
  40. #define NTFS_DT_REG             8
  41. #define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
  42. #include "types.h"
  43. #include "common.h"
  44. #include "intrface.h"
  45. #include "ntfs.h"
  46. #include "dir.h"
  47. struct list_dir_struct {
  48.     t_file_data *dir_list;
  49.     t_file_data *current_file;
  50.     ntfs_volume *vol;
  51. };
  52.  
  53. /*
  54.  * This is the "ntfs_filldir" function type, used by ntfs_readdir() to let
  55.  * the caller specify what kind of dirent layout it wants to have.
  56.  * This allows the caller to read directories into their application or
  57.  * to have different dirent layouts depending on the binary type.
  58.  */
  59. typedef int (*ntfs_filldir_t)(void *dirent, const uchar_t *name,
  60.                 const int name_len, const int name_type, const s64 pos,
  61.                 const MFT_REF mref, const unsigned dt_type);
  62.  
  63. extern struct ntfs_device_operations ntfs_device_testdisk_io_ops;
  64.  
  65. extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
  66.                 void *dirent, ntfs_filldir_t filldir);
  67. extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
  68.                 const uchar_t *uname, const int uname_len);
  69. time_t ntfs2utc (s64 ntfstime);
  70. int list_entry(  struct list_dir_struct *ls, const uchar_t *name, 
  71.         const int name_len, const int name_type, const s64 pos,
  72.         const MFT_REF mref, const unsigned dt_type);
  73. ntfs_inode * utils_pathname_to_inode (ntfs_volume *vol, ntfs_inode *parent, const char *pathname);
  74. ATTR_RECORD * find_attribute (const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
  75.  
  76. /**
  77.  * ntfs2utc - Convert an NTFS time to Unix time
  78.  * @time:  An NTFS time in 100ns units since 1601
  79.  *
  80.  * NTFS stores times as the number of 100ns intervals since January 1st 1601 at
  81.  * 00:00 UTC.  This system will not suffer from Y2K problems until ~57000AD.
  82.  *
  83.  * Return:  n  A Unix time (number of seconds since 1970)
  84.  */
  85. time_t ntfs2utc (s64 ntfstime)
  86. {
  87.   return (ntfstime - (NTFS_TIME_OFFSET)) / 10000000;
  88. }
  89.  
  90. /**
  91.  * list_entry
  92.  * FIXME: Should we print errors as we go along? (AIA)
  93.  */
  94. int list_entry(  struct list_dir_struct *ls, const uchar_t *name, 
  95.         const int name_len, const int name_type, const s64 pos,
  96.         const MFT_REF mref, const unsigned dt_type)
  97. {
  98.   char *filename = NULL;
  99.   int result = 0;
  100.  
  101.   filename = calloc (1, MAX_PATH);
  102.   if (!filename)
  103.     return -1;
  104.  
  105.   if (ntfs_ucstombs (name, name_len, &filename, MAX_PATH) < 0) {
  106.     ecrit_rapport("Cannot represent filename in current locale.\n");
  107.     goto free;
  108.   }
  109.  
  110.   result = 0;                    /* These are successful */
  111.   if (filename[0] == '$')            /* system */
  112.     goto free;
  113.   /* Keep FILE_NAME_WIN32 and FILE_NAME_POSIX */
  114.   if ((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS)
  115.     goto free;
  116.   {
  117.     s64 filesize = 0;
  118.     ntfs_inode *ni;
  119.     ntfs_attr_search_ctx *ctx = NULL;
  120.     FILE_NAME_ATTR *file_name_attr;
  121.     ATTR_RECORD *attr;
  122.  
  123.     result = -1;                /* Everything else is bad */
  124.  
  125.     ni = ntfs_inode_open(ls->vol, mref);
  126.     if (!ni)
  127.       goto release;
  128.  
  129.     ctx = ntfs_attr_get_search_ctx(ni, ni->mrec);
  130.     if (!ctx)
  131.       goto release;
  132.  
  133.     if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL,
  134.       0, ctx))
  135.       goto release;
  136.     attr = ctx->attr;
  137.  
  138.     file_name_attr = (FILE_NAME_ATTR *)((char *)attr +
  139.     le16_to_cpu(attr->value_offset));
  140.     if (!file_name_attr)
  141.       goto release;
  142.  
  143.  
  144.     if (dt_type != NTFS_DT_DIR) {
  145.       if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0,
  146.         NULL, 0, ctx))
  147.     filesize = ntfs_get_attribute_value_length(
  148.         ctx->attr);
  149.     }
  150.  
  151.     /*        if (opts.inode) */
  152.     /*            printf("%7lld    %8lld %s %s\n", MREF(mref), filesize, */
  153.     /*                    t_buf + 4, filename); */
  154.     /*        else */
  155.     {
  156.       t_file_data *new_file=MALLOC(sizeof(*new_file));
  157.       memcpy(new_file->name,filename,(MAX_PATH<sizeof(new_file->name)?MAX_PATH:sizeof(new_file->name)));
  158.       new_file->prev=ls->current_file;
  159.       new_file->next=NULL;
  160.       new_file->filestat.st_dev=0;
  161.       new_file->filestat.st_ino=MREF(mref);
  162.       new_file->filestat.st_mode = (dt_type == NTFS_DT_DIR?LINUX_S_IFDIR| LINUX_S_IRUGO | LINUX_S_IXUGO:LINUX_S_IFREG | LINUX_S_IRUGO);
  163.       new_file->filestat.st_nlink=0;
  164.       new_file->filestat.st_uid=0;
  165.       new_file->filestat.st_gid=0;
  166.       new_file->filestat.st_rdev=0;
  167.       new_file->filestat.st_size=filesize;
  168.       new_file->filestat.st_blksize=SECTOR_SIZE;
  169. #ifndef DJGPP
  170.       if(new_file->filestat.st_blksize!=0)
  171.       {
  172.     new_file->filestat.st_blocks=(new_file->filestat.st_size+new_file->filestat.st_blksize-1)/new_file->filestat.st_blksize;
  173.       }
  174. #endif
  175.       new_file->filestat.st_atime=ntfs2utc(sle64_to_cpu(file_name_attr->last_access_time));
  176.       new_file->filestat.st_ctime=ntfs2utc(sle64_to_cpu(file_name_attr->creation_time));
  177.       new_file->filestat.st_mtime=ntfs2utc(sle64_to_cpu(file_name_attr->last_data_change_time));
  178.       new_file->prev=ls->current_file;
  179.       new_file->next=NULL;
  180.       /* ecrit_rapport("fat: new file %s de=%p size=%u\n",new_file->name,de,de->size); */
  181.       /*    fat_write_rapport(new_fat_element); */
  182.       if(ls->current_file!=NULL)
  183.     ls->current_file->next=new_file;
  184.       else
  185.     ls->dir_list=new_file;
  186.       ls->current_file=new_file;
  187.     }
  188.  
  189.     result = 0;
  190. release:
  191.     /* Release atrtibute search context and close the inode. */
  192.     if (ctx)
  193.       ntfs_attr_put_search_ctx(ctx);
  194.     if (ni)
  195.       ntfs_inode_close(ni);
  196.   }
  197. free:
  198.   free (filename);
  199.   return result;
  200. }
  201.  
  202. /**
  203.  * ntfs_mount - open ntfs volume
  204.  * @name:    name of device/file to open
  205.  * @rwflag:    optional mount flags
  206.  *
  207.  * This function mounts an ntfs volume. @name should contain the name of the
  208.  * device/file to mount as the ntfs volume.
  209.  *
  210.  * @rwflags is an optional second parameter. The same flags are used as for
  211.  * the mount system call (man 2 mount). Currently only the following flag
  212.  * is implemented:
  213.  *    MS_RDONLY    - mount volume read-only
  214.  *
  215.  * The function opens the device or file @name and verifies that it contains a
  216.  * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
  217.  * some of the values inside the structure from the information stored in the
  218.  * bootsector. It proceeds to load the necessary system files and completes
  219.  * setting up the structure.
  220.  *
  221.  * Return the allocated volume structure on success and NULL on error with
  222.  * errno set to the error code.
  223.  *
  224.  * Note, that a copy is made of @name, and hence it can be discarded as
  225.  * soon as the function returns.
  226.  */
  227.  
  228.  
  229. /**
  230.  * utils_pathname_to_inode - Find the inode which represents the given pathname
  231.  * @vol:       An ntfs volume obtained from ntfs_mount
  232.  * @parent:    A directory inode to begin the search (may be NULL)
  233.  * @pathname:  Pathname to be located
  234.  *
  235.  * Take an ASCII pathname and find the inode that represents it.  The function
  236.  * splits the path and then descends the directory tree.  If @parent is NULL,
  237.  * then the root directory '.' will be used as the base for the search.
  238.  *
  239.  * Return:  inode  Success, the pathname was valid
  240.  *        NULL   Error, the pathname was invalid, or some other error occurred
  241.  */
  242. ntfs_inode * utils_pathname_to_inode (ntfs_volume *vol, ntfs_inode *parent, const char *pathname)
  243. {
  244.     u64 inum;
  245.     int len;
  246.     char *p, *q;
  247.     ntfs_inode *ni;
  248.     ntfs_inode *result  = NULL;
  249.     uchar_t    *unicode = NULL;
  250.     char       *ascii   = NULL;
  251.  
  252.     if (!vol || !pathname) {
  253.         errno = EINVAL;
  254.         return NULL;
  255.     }
  256.  
  257.     if (parent) {
  258.         ni = parent;
  259.     } else {
  260.         ni = ntfs_inode_open (vol, FILE_root);
  261.         if (!ni) {
  262.             ecrit_rapport("Couldn't open the inode of the root directory.\n");
  263.             goto close;
  264.         }
  265.     }
  266.  
  267.     unicode = calloc (1, MAX_PATH);
  268.     ascii   = strdup (pathname);        /* Work with a r/w copy */
  269.     if (!unicode || !ascii) {
  270.         ecrit_rapport("Out of memory.\n");
  271.         goto close;
  272.     }
  273.  
  274.     p = ascii;
  275.     while (p && *p && *p == PATH_SEP)    /* Remove leading /'s */
  276.         p++;
  277.     while (p && *p) {
  278.         q = strchr (p, PATH_SEP);    /* Find the end of the first token */
  279.         if (q != NULL) {
  280.             *q = '\0';
  281.             q++;
  282.         }
  283.  
  284.         len = ntfs_mbstoucs (p, &unicode, MAX_PATH);
  285.         if (len < 0) {
  286.             ecrit_rapport("Couldn't convert name to Unicode: %s.\n", p);
  287.             goto close;
  288.         }
  289.  
  290.         inum = ntfs_inode_lookup_by_name (ni, unicode, len);
  291.         if (inum == (u64)-1) {
  292.             ecrit_rapport("Couldn't find name '%s' in pathname '%s'.\n", p, pathname);
  293.             goto close;
  294.         }
  295.  
  296.         if (ni != parent)
  297.             ntfs_inode_close (ni);
  298.  
  299.         ni = ntfs_inode_open (vol, inum);
  300.         if (!ni) {
  301.             ecrit_rapport("Cannot open inode %lld: %s.\n", inum, p);
  302.             goto close;
  303.         }
  304.  
  305.         p = q;
  306.         while (p && *p && *p == PATH_SEP)
  307.             p++;
  308.     }
  309.  
  310.     result = ni;
  311.     ni = NULL;
  312. close:
  313.     if (ni && (ni != parent))
  314.         ntfs_inode_close (ni);
  315.     free (ascii);
  316.     free (unicode);
  317.     return result;
  318. }
  319.  
  320. /**
  321.  * find_attribute - Find an attribute of the given type
  322.  * @type:  An attribute type, e.g. AT_FILE_NAME
  323.  * @ctx:   A search context, created using ntfs_get_attr_search_ctx
  324.  *
  325.  * Using the search context to keep track, find the first/next occurrence of a
  326.  * given attribute type.
  327.  *
  328.  * N.B.  This will return a pointer into @mft.  As long as the search context
  329.  *       has been created without an inode, it won't overflow the buffer.
  330.  *
  331.  * Return:  Pointer  Success, an attribute was found
  332.  *          NULL     Error, no matching attributes were found
  333.  */
  334. ATTR_RECORD * find_attribute (const ATTR_TYPES type, ntfs_attr_search_ctx *ctx)
  335. {
  336.         if (!ctx) {
  337.                 errno = EINVAL;
  338.                 return NULL;
  339.         }
  340.                                                                                                                              
  341.         if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) {
  342.                 ecrit_rapport("find_attribute didn't find an attribute of type: 0x%02x.\n", type);
  343.                 return NULL;    /* None / no more of that type */
  344.         }
  345.                                                                                                                              
  346.         ecrit_rapport("find_attribute found an attribute of type: 0x%02x.\n", type);
  347.         return ctx->attr;
  348. }
  349.  
  350. t_file_data *ntfs_dir(t_param_disk *disk_car, const t_diskext *partition, t_dir_data *dir_data, const unsigned long int cluster);
  351. t_file_data *ntfs_dir(t_param_disk *disk_car, const t_diskext *partition, t_dir_data *dir_data, const unsigned long int cluster)
  352. {
  353.   ntfs_inode *ni;
  354.   s64 pos;
  355.   struct list_dir_struct *ls=(struct list_dir_struct*)dir_data->private_dir_data;
  356.   ls->dir_list=NULL;
  357.   ls->current_file=NULL;
  358.  
  359.   ni = utils_pathname_to_inode (ls->vol, NULL, dir_data->current_directory);
  360.   if (!ni) {
  361.     /* FIXME: Print error... (AIA) */
  362.     return NULL;
  363.   }
  364.  
  365.   /*
  366.    * We now are at the final path component.  If it is a file just
  367.    * list it.  If it is a directory, list its contents.
  368.    */
  369.   pos = 0;
  370.   if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
  371.     ntfs_readdir(ni, &pos, ls, (ntfs_filldir_t)list_entry);
  372.     /* FIXME: error checking... (AIA) */
  373.   }
  374.   #ifdef NEW
  375.   else {
  376.     ATTR_RECORD *rec;
  377.     FILE_NAME_ATTR *attr;
  378.     ntfs_attr_search_ctx *ctx;
  379.     int space = 4;
  380.     uchar_t *name = NULL;
  381.     int name_len = 0;;
  382.  
  383.     ctx = ntfs_attr_get_search_ctx (NULL, ni->mrec);
  384.     if (!ctx)
  385.       return ls->dir_list;
  386.  
  387.     while ((rec = find_attribute (AT_FILE_NAME, ctx))) {
  388.       /* We know this will always be resident. */
  389.       attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu (rec->value_offset));
  390.  
  391.       if (attr->file_name_type < space) {
  392.     name     = attr->file_name;
  393.     name_len = attr->file_name_length;
  394.     space    = attr->file_name_type;
  395.       }
  396.     }
  397.  
  398.     list_entry(ls, name, name_len, space, pos, ni->mft_no, NTFS_DT_REG);
  399.     /* FIXME: error checking... (AIA) */
  400.  
  401.     ntfs_attr_put_search_ctx(ctx);
  402.   }
  403. #endif
  404.  
  405.   /* Finished with the inode; release it. */
  406.   ntfs_inode_close(ni);
  407.  
  408.   return ls->dir_list;
  409. }
  410.  
  411. /**
  412.  * main - Begin here
  413.  *
  414.  * Start from here.
  415.  *
  416.  * Return:  0  Success, the program worked
  417.  *        1  Error, parsing mount options failed
  418.  *        2  Error, mount attempt failed
  419.  *        3  Error, failed to open root directory
  420.  *        4  Error, failed to open directory in search path
  421.  */
  422. int dir_partition_ntfs(WINDOW *window,t_param_disk *disk_car,t_diskext *partition, const int debug)
  423. {
  424.   t_my_data my_data;
  425.   static struct ntfs_device *dev;
  426.   ntfs_volume *vol=NULL;
  427.   aff_buffer(BUFFER_RESET,"Q");
  428.   wmove(window,4,0);
  429.   aff_part(window,AFF_PART_NL,disk_car,partition);
  430.   ecrit_rapport("\n");
  431.   aff_part_rapport(disk_car,partition);
  432.   my_data.partition=partition;
  433.   my_data.disk_car=disk_car;
  434.   my_data.offset=0;
  435.   dev = ntfs_device_alloc("/", 0, &ntfs_device_testdisk_io_ops, NULL);
  436.   if (dev)
  437.   {
  438.     dev->d_private=&my_data;
  439.     /* Call ntfs_device_mount() to do the actual mount. */
  440.     vol = ntfs_device_mount(dev, MS_RDONLY);
  441.   }
  442.   if (!vol) {
  443.     ecrit_rapport("Couldn't mount device %s\n", strerror (errno));
  444.     return 2;
  445.   }
  446.  
  447.   if (vol->flags & VOLUME_IS_DIRTY) {
  448.     ecrit_rapport("Volume is dirty.\n");
  449. /*   ntfs_umount (vol, FALSE); */
  450. /*   return 2; */
  451.   }
  452.   {
  453.     struct list_dir_struct ls;
  454.     t_dir_data dir_data;
  455.     ls.dir_list=NULL;
  456.     ls.current_file=NULL;
  457.     ls.vol=vol;
  458.     dir_data.window=window;
  459.     dir_data.debug=debug;
  460.     dir_data.private_dir_data=&ls;
  461.     dir_data.get_dir=ntfs_dir;
  462.     strncpy(dir_data.current_directory,"/",sizeof(dir_data.current_directory));
  463.     dir_partition(disk_car,partition,&dir_data,2);
  464.   }  
  465.   ntfs_umount(vol, FALSE);
  466.   return 0;
  467. }
  468. #else
  469. #include "types.h"
  470. #include "common.h"
  471. #include "intrface.h"
  472.  
  473. int dir_partition_ntfs(WINDOW *window,t_param_disk *disk_car,t_diskext *partition)
  474. {
  475.   aff_buffer(BUFFER_RESET,"Q");
  476.   wmove(stdscr,5,0);
  477.   aff_part(window,AFF_PART_NONL,disk_car,partition);
  478.   aff_part_rapport(disk_car,partition);
  479.   aff_buffer(BUFFER_ADD,"Recompile with ntfsprogs library");
  480.   aff_buffer(BUFFER_DISPLAY,"Q",window);
  481.   return 0;
  482. }
  483. #endif
  484.